Namespace xpComponent.KeyBoard
    Public Class KeyBoards

    End Class

    Public Enum KeyToggleStatus As Integer
        StatusOn = 0
        StatusOff
    End Enum

    Public Enum ToggleKey As Integer
        CapsLock = 0
        NumLock
        ScrollLock
    End Enum

    Public Class ToggleKeyControl
        'Declare these in a module somewhere
        Public Const VK_NUMLOCK As Short = &H90S
        Public Const VK_SCROLL As Short = &H91S
        Public Const VK_CAPITAL As Short = &H14S
        Public Const KEYEVENTF_EXTENDEDKEY As Short = &H1S
        Public Const KEYEVENTF_KEYUP As Short = &H2S
        Public Const VER_PLATFORM_WIN32_NT As Short = 2
        Public Const VER_PLATFORM_WIN32_WINDOWS As Short = 1

        Private Structure OSVERSIONINFO
            Dim dwOSVersionInfoSize As Integer
            Dim dwMajorVersion As Integer
            Dim dwMinorVersion As Integer
            Dim dwBuildNumber As Integer
            Dim dwPlatformId As Integer
            <VBFixedString(128), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=128)> Public szCSDVersion As String '  Maintenance string for PSS usage
        End Structure

        ' API declarations:
        Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (ByRef lpVersionInformation As OSVERSIONINFO) As Integer
        Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
        Private Declare Function GetKeyboardState Lib "user32" (ByRef pbKeyState As Byte) As Integer
        Private Declare Function SetKeyboardState Lib "user32" (ByRef lppbKeyState As Byte) As Integer

        Public Shared Sub SetLock(ByVal targetKey As ToggleKey, ByVal status As KeyToggleStatus)
            Dim o As OSVERSIONINFO
            o.dwOSVersionInfoSize = Len(o)
            GetVersionEx(o)
            Dim keys(255) As Byte
            Dim index As Short
            GetKeyboardState(keys(0))
            If GetLockStatus(targetKey) = status Then
                'Nothing to do as the required status is already set
            Else
                Select Case targetKey
                    Case ToggleKey.CapsLock : index = VK_CAPITAL
                    Case ToggleKey.NumLock : index = VK_NUMLOCK
                    Case ToggleKey.ScrollLock : index = VK_SCROLL
                End Select
                If status = KeyToggleStatus.StatusOn Then
                    If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98
                        keys(index) = 1
                        SetKeyboardState(keys(0))
                    ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then  '=== WinNT
                        'Simulate Key Press
                        keybd_event(index, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)
                        'Simulate Key Release
                        keybd_event(index, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
                    End If
                Else
                    If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98
                        keys(index) = 0
                        SetKeyboardState(keys(0))
                    ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then  '=== WinNT
                        'Simulate Key Press
                        keybd_event(index, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)
                        'Simulate Key Release
                        keybd_event(index, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
                    End If
                End If
            End If
        End Sub

        Public Shared Function GetLockStatus(ByVal targetKey As ToggleKey) As xpComponent.KeyBoard.KeyToggleStatus
            Dim LockState As Boolean = False
            Dim keys(255) As Byte
            GetKeyboardState(keys(0))
            Select Case targetKey
                Case ToggleKey.CapsLock : LockState = keys(VK_CAPITAL)
                Case ToggleKey.NumLock : LockState = keys(VK_NUMLOCK)
                Case ToggleKey.ScrollLock : LockState = keys(VK_SCROLL)
            End Select
            Return ToKeyToggleStatus(LockState)
        End Function

        Public Shared Function ToKeyToggleStatus(ByVal value As Boolean) As KeyToggleStatus
            If value Then
                Return KeyToggleStatus.StatusOn
            Else
                Return KeyToggleStatus.StatusOff
            End If
        End Function
    End Class
End Namespace